using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text;
using System.Text.Json;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Services.Search
{
    /// <summary>
    /// Elasticsearch搜索服务
    /// 提供全文搜索、索引管理、数据分析等功能
    /// </summary>
    public class ElasticsearchService : IElasticsearchService, IDisposable
    {
        private readonly ElasticsearchOptions _options;
        private readonly ILogger<ElasticsearchService> _logger;
        private readonly HttpClient _httpClient;
        private bool _disposed;

        public ElasticsearchService(
            IOptions<ElasticsearchOptions> options,
            ILogger<ElasticsearchService> logger)
        {
            _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            _httpClient = new HttpClient
            {
                BaseAddress = new Uri(_options.Endpoint),
                Timeout = TimeSpan.FromSeconds(_options.TimeoutSeconds)
            };

            // 设置认证
            if (!string.IsNullOrEmpty(_options.Username) && !string.IsNullOrEmpty(_options.Password))
            {
                var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_options.Username}:{_options.Password}"));
                _httpClient.DefaultRequestHeaders.Authorization = 
                    new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
            }

            _logger.LogInformation("Elasticsearch服务已初始化，端点: {Endpoint}", _options.Endpoint);
        }

        /// <summary>
        /// 检查连接状态
        /// </summary>
        public async Task<bool> IsHealthyAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync("/_cluster/health");
                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    var healthInfo = JsonSerializer.Deserialize<JsonElement>(content);
                    
                    if (healthInfo.TryGetProperty("status", out var statusElement))
                    {
                        var status = statusElement.GetString();
                        _logger.LogDebug("Elasticsearch集群状态: {Status}", status);
                        return status == "green" || status == "yellow";
                    }
                }

                _logger.LogWarning("Elasticsearch健康检查失败，状态码: {StatusCode}", response.StatusCode);
                return false;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Elasticsearch健康检查异常");
                return false;
            }
        }

        /// <summary>
        /// 创建索引
        /// </summary>
        public async Task<ElasticsearchResult> CreateIndexAsync(string indexName, object? mapping = null)
        {
            try
            {
                var indexRequest = new
                {
                    settings = new
                    {
                        number_of_shards = _options.DefaultShards,
                        number_of_replicas = _options.DefaultReplicas,
                        analysis = new
                        {
                            analyzer = new
                            {
                                ik_smart = new { type = "ik_smart" },
                                ik_max_word = new { type = "ik_max_word" }
                            }
                        }
                    },
                    mappings = mapping ?? GetDefaultMapping()
                };

                var json = JsonSerializer.Serialize(indexRequest, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });

                var response = await _httpClient.PutAsync($"/{indexName}", 
                    new StringContent(json, Encoding.UTF8, "application/json"));

                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    _logger.LogInformation("索引创建成功: {IndexName}", indexName);
                    return new ElasticsearchResult
                    {
                        Success = true,
                        Message = "索引创建成功",
                        Data = responseContent
                    };
                }
                else
                {
                    _logger.LogError("索引创建失败: {IndexName}, 响应: {Response}", indexName, responseContent);
                    return new ElasticsearchResult
                    {
                        Success = false,
                        Message = $"索引创建失败: {response.StatusCode}",
                        Error = responseContent
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建索引时发生异常: {IndexName}", indexName);
                return new ElasticsearchResult
                {
                    Success = false,
                    Message = ex.Message,
                    Error = ex.ToString()
                };
            }
        }

        /// <summary>
        /// 删除索引
        /// </summary>
        public async Task<ElasticsearchResult> DeleteIndexAsync(string indexName)
        {
            try
            {
                var response = await _httpClient.DeleteAsync($"/{indexName}");
                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    _logger.LogInformation("索引删除成功: {IndexName}", indexName);
                    return new ElasticsearchResult
                    {
                        Success = true,
                        Message = "索引删除成功",
                        Data = responseContent
                    };
                }
                else
                {
                    _logger.LogError("索引删除失败: {IndexName}, 响应: {Response}", indexName, responseContent);
                    return new ElasticsearchResult
                    {
                        Success = false,
                        Message = $"索引删除失败: {response.StatusCode}",
                        Error = responseContent
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除索引时发生异常: {IndexName}", indexName);
                return new ElasticsearchResult
                {
                    Success = false,
                    Message = ex.Message,
                    Error = ex.ToString()
                };
            }
        }

        /// <summary>
        /// 检查索引是否存在
        /// </summary>
        public async Task<bool> IndexExistsAsync(string indexName)
        {
            try
            {
                var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, $"/{indexName}"));
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查索引存在性时发生异常: {IndexName}", indexName);
                return false;
            }
        }

        /// <summary>
        /// 添加文档
        /// </summary>
        public async Task<ElasticsearchResult> IndexDocumentAsync<T>(string indexName, string documentId, T document)
        {
            try
            {
                var json = JsonSerializer.Serialize(document, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });

                var response = await _httpClient.PutAsync($"/{indexName}/_doc/{documentId}",
                    new StringContent(json, Encoding.UTF8, "application/json"));

                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    _logger.LogDebug("文档索引成功: {IndexName}/{DocumentId}", indexName, documentId);
                    return new ElasticsearchResult
                    {
                        Success = true,
                        Message = "文档索引成功",
                        Data = responseContent
                    };
                }
                else
                {
                    _logger.LogError("文档索引失败: {IndexName}/{DocumentId}, 响应: {Response}", 
                        indexName, documentId, responseContent);
                    return new ElasticsearchResult
                    {
                        Success = false,
                        Message = $"文档索引失败: {response.StatusCode}",
                        Error = responseContent
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "索引文档时发生异常: {IndexName}/{DocumentId}", indexName, documentId);
                return new ElasticsearchResult
                {
                    Success = false,
                    Message = ex.Message,
                    Error = ex.ToString()
                };
            }
        }

        /// <summary>
        /// 批量索引文档
        /// </summary>
        public async Task<ElasticsearchResult> BulkIndexAsync<T>(string indexName, IEnumerable<(string Id, T Document)> documents)
        {
            try
            {
                var bulkBody = new StringBuilder();
                foreach (var (id, document) in documents)
                {
                    var indexAction = JsonSerializer.Serialize(new { index = new { _index = indexName, _id = id } });
                    var documentJson = JsonSerializer.Serialize(document, new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                    });

                    bulkBody.AppendLine(indexAction);
                    bulkBody.AppendLine(documentJson);
                }

                var response = await _httpClient.PostAsync("/_bulk",
                    new StringContent(bulkBody.ToString(), Encoding.UTF8, "application/x-ndjson"));

                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    var bulkResponse = JsonSerializer.Deserialize<JsonElement>(responseContent);
                    var hasErrors = bulkResponse.TryGetProperty("errors", out var errorsElement) && 
                                   errorsElement.GetBoolean();

                    if (!hasErrors)
                    {
                        _logger.LogInformation("批量索引成功: {IndexName}, 文档数: {Count}", 
                            indexName, documents.Count());
                        return new ElasticsearchResult
                        {
                            Success = true,
                            Message = "批量索引成功",
                            Data = responseContent
                        };
                    }
                    else
                    {
                        _logger.LogWarning("批量索引部分失败: {IndexName}, 响应: {Response}", 
                            indexName, responseContent);
                        return new ElasticsearchResult
                        {
                            Success = false,
                            Message = "批量索引部分失败",
                            Error = responseContent
                        };
                    }
                }
                else
                {
                    _logger.LogError("批量索引失败: {IndexName}, 响应: {Response}", indexName, responseContent);
                    return new ElasticsearchResult
                    {
                        Success = false,
                        Message = $"批量索引失败: {response.StatusCode}",
                        Error = responseContent
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量索引时发生异常: {IndexName}", indexName);
                return new ElasticsearchResult
                {
                    Success = false,
                    Message = ex.Message,
                    Error = ex.ToString()
                };
            }
        }

        /// <summary>
        /// 搜索文档
        /// </summary>
        public async Task<ElasticsearchSearchResult<T>> SearchAsync<T>(string indexName, object query, int from = 0, int size = 10)
        {
            try
            {
                var searchRequest = new
                {
                    from,
                    size,
                    query,
                    highlight = new
                    {
                        fields = new
                        {
                            title = new { },
                            content = new { }
                        }
                    }
                };

                var json = JsonSerializer.Serialize(searchRequest, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });

                var response = await _httpClient.PostAsync($"/{indexName}/_search",
                    new StringContent(json, Encoding.UTF8, "application/json"));

                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    var searchResponse = JsonSerializer.Deserialize<JsonElement>(responseContent);
                    var hits = searchResponse.GetProperty("hits");
                    var totalHits = hits.GetProperty("total");
                    
                    var total = totalHits.TryGetProperty("value", out var totalValue) 
                        ? totalValue.GetInt64() 
                        : hits.GetProperty("hits").GetArrayLength();

                    var documents = new List<ElasticsearchDocument<T>>();
                    
                    foreach (var hit in hits.GetProperty("hits").EnumerateArray())
                    {
                        var source = hit.GetProperty("_source");
                        var document = JsonSerializer.Deserialize<T>(source.GetRawText(), new JsonSerializerOptions
                        {
                            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                        });

                        var esDocument = new ElasticsearchDocument<T>
                        {
                            Id = hit.GetProperty("_id").GetString() ?? "",
                            Source = document,
                            Score = hit.TryGetProperty("_score", out var scoreElement) ? scoreElement.GetSingle() : 0f
                        };

                        // 添加高亮信息
                        if (hit.TryGetProperty("highlight", out var highlightElement))
                        {
                            esDocument.Highlight = JsonSerializer.Deserialize<Dictionary<string, string[]>>(
                                highlightElement.GetRawText()) ?? new Dictionary<string, string[]>();
                        }

                        documents.Add(esDocument);
                    }

                    _logger.LogDebug("搜索完成: {IndexName}, 查询: {Query}, 结果数: {Total}", 
                        indexName, json, total);

                    return new ElasticsearchSearchResult<T>
                    {
                        Success = true,
                        Total = total,
                        Documents = documents,
                        From = from,
                        Size = size
                    };
                }
                else
                {
                    _logger.LogError("搜索失败: {IndexName}, 响应: {Response}", indexName, responseContent);
                    return new ElasticsearchSearchResult<T>
                    {
                        Success = false,
                        Error = $"搜索失败: {response.StatusCode}",
                        Documents = new List<ElasticsearchDocument<T>>()
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "搜索时发生异常: {IndexName}", indexName);
                return new ElasticsearchSearchResult<T>
                {
                    Success = false,
                    Error = ex.Message,
                    Documents = new List<ElasticsearchDocument<T>>()
                };
            }
        }

        /// <summary>
        /// 删除文档
        /// </summary>
        public async Task<ElasticsearchResult> DeleteDocumentAsync(string indexName, string documentId)
        {
            try
            {
                var response = await _httpClient.DeleteAsync($"/{indexName}/_doc/{documentId}");
                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    _logger.LogDebug("文档删除成功: {IndexName}/{DocumentId}", indexName, documentId);
                    return new ElasticsearchResult
                    {
                        Success = true,
                        Message = "文档删除成功",
                        Data = responseContent
                    };
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    _logger.LogWarning("文档不存在: {IndexName}/{DocumentId}", indexName, documentId);
                    return new ElasticsearchResult
                    {
                        Success = true,
                        Message = "文档不存在或已删除",
                        Data = responseContent
                    };
                }
                else
                {
                    _logger.LogError("文档删除失败: {IndexName}/{DocumentId}, 响应: {Response}", 
                        indexName, documentId, responseContent);
                    return new ElasticsearchResult
                    {
                        Success = false,
                        Message = $"文档删除失败: {response.StatusCode}",
                        Error = responseContent
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除文档时发生异常: {IndexName}/{DocumentId}", indexName, documentId);
                return new ElasticsearchResult
                {
                    Success = false,
                    Message = ex.Message,
                    Error = ex.ToString()
                };
            }
        }

        /// <summary>
        /// 获取默认映射
        /// </summary>
        private object GetDefaultMapping()
        {
            return new
            {
                properties = new
                {
                    title = new
                    {
                        type = "text",
                        analyzer = "ik_max_word",
                        search_analyzer = "ik_smart"
                    },
                    content = new
                    {
                        type = "text",
                        analyzer = "ik_max_word",
                        search_analyzer = "ik_smart"
                    },
                    category = new
                    {
                        type = "keyword"
                    },
                    tags = new
                    {
                        type = "keyword"
                    },
                    createdAt = new
                    {
                        type = "date"
                    },
                    updatedAt = new
                    {
                        type = "date"
                    }
                }
            };
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (_disposed) return;

            _httpClient?.Dispose();
            _disposed = true;
        }
    }
}
